package com.nq.fund;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.nq.dao.*;
import com.nq.dao.fund.StFundKlineMapper;
import com.nq.dao.fund.StFundMapper;
import com.nq.dao.fund.StFundMovementMapper;
import com.nq.fund.entity.StFund;
import com.nq.fund.entity.StFundKline;
import com.nq.fund.entity.StFundMovement;
import com.nq.pojo.StFundApply;
import com.nq.pojo.StFundApplyDetail;
import com.nq.pojo.User;
import com.nq.pojo.UserCashDetail;
import com.nq.service.IUserService;
import com.nq.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

@Component
@Slf4j
public class FundSimulatorComponent {

    @Resource
    private UserMapper userMapper;
    @Resource
    private StFundMapper fundMapper;
    @Resource
    private UserCashDetailMapper userCashDetailMapper;
    @Resource
    private FundsApplyMapper fundsApplyMapper;
    @Resource
    private StFundKlineMapper fundKlineMapper;
    @Resource
    private StFundMovementMapper fundMovementMapper;
    @Resource
    private StFundApplyMapper stFundApplyMapper;
    @Resource
    private StFundApplyDetailMapper stFundApplyDetailMapper;
    @Resource
    private IUserService iUserService;


    private static final double INITIAL_PRICE = 10.0; // 初始价格
    private static final double MAX_FLUCTUATION = 2.0; // 最大波动范围 处于正负之间
    private static final double SLOW_TREND = 0.05; // 缓慢上涨的趋势

    private double currentPrice;

    public FundSimulatorComponent() {
        this.currentPrice = INITIAL_PRICE;
    }

    /**
     * 查询所有的基金信息
     * 在 0点0分 执行一次 每天只需要执行一次
     * 同时计算所有基金的收益
     */
//    @PostConstruct
//    @Scheduled(cron = "0 0 12 * * ?")
    public void queryAllFund(){
        execute();
    }

    public void execute(){
        log.info("基金生成K线开始执行");
        // 查询出所有的基金信息，进行模拟K线
        QueryWrapper<StFund> stFundQueryWrapper = new QueryWrapper<>();
        stFundQueryWrapper.eq("status", "1");
        List<StFund> stFunds = fundMapper.selectList(stFundQueryWrapper);

        for (StFund stFund : stFunds) {
            Integer fundId = stFund.getId();
            String fundCode = stFund.getFundCode();
            // 当前价格
            BigDecimal currentPrice = stFund.getCurrentPrice();
            // 最大波动范围
            BigDecimal maxFluctuation = stFund.getMaxFluctuation();
            // 上涨趋势
            BigDecimal upwardTrend = stFund.getUpwardTrend();

            // 模拟K线
            generatedFundMovement(fundId, fundCode, currentPrice, maxFluctuation, upwardTrend);

        }

        log.info("基金生成K线结束执行");
    }

    public BigDecimal simulatePrice(BigDecimal initialPrice, BigDecimal maxFluctuation, BigDecimal upwardTrend) {
        Random random = new Random();

        // 生成随机波动
        BigDecimal fluctuation = maxFluctuation.multiply(BigDecimal.valueOf(random.nextDouble() * 2 - 1));

        // 缓慢上涨的趋势
        BigDecimal slowTrend = upwardTrend;

        // 计算下一个价格
        BigDecimal nextPrice = initialPrice.add(fluctuation).add(slowTrend);

        // 确保价格不会小于等于 0
        if (nextPrice.compareTo(BigDecimal.ZERO) > 0) {
            initialPrice = nextPrice;
        }

        System.out.println("当前基金价格：" + initialPrice);
        return initialPrice;
    }

    // 生成每日最新基金净值数据
    public void generatedFundMovement(Integer fundId, String fundCode, BigDecimal initialPrice, BigDecimal maxFluctuation, BigDecimal upwardTrend){

        BigDecimal common = new BigDecimal("5");
        BigDecimal max = maxFluctuation.divide(common, 4, RoundingMode.HALF_UP);
        BigDecimal upward = upwardTrend.divide(common, 4, RoundingMode.HALF_UP);

        // 查询昨天的收盘价格  时间倒序查询最后一次的数据
        QueryWrapper<StFundKline> klineQueryWrapper = new QueryWrapper<>();
        klineQueryWrapper.eq("fund_code", fundCode);
        klineQueryWrapper.orderByDesc("timestamp");
        klineQueryWrapper.last(" limit 1");
        StFundKline stFundKline = fundKlineMapper.selectOne(klineQueryWrapper);

        BigDecimal previousPrice = new BigDecimal("0"); // 用于存储上一次的价格
        if (null != stFundKline) {
            BigDecimal close = stFundKline.getClose();
            previousPrice = close;
        }

        // 记录当前循环中的最大值
        BigDecimal high = new BigDecimal("0");
        // 记录当前循环中的最小值
        BigDecimal low = new BigDecimal("0");
        BigDecimal open = new BigDecimal("0");
        BigDecimal close = new BigDecimal("0");

        double volume = Math.round(Math.random() * 100) + 10;
        BigDecimal volumeBigDecimal = BigDecimal.valueOf(volume); // 将volume转换为BigDecimal对象

        for (int i = 0; i < 5; i++) {
            BigDecimal currentPrice = simulatePrice(initialPrice, max, upward);

            // 计算涨跌幅百分比
            BigDecimal priceChangePercentage;
            if (previousPrice.compareTo(BigDecimal.ZERO) == 0) {
                // 如果previousPrice为0，则将价格变化百分比设置为当前价格除以100
                priceChangePercentage = currentPrice.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
            } else {
                // 否则，执行常规的价格变化百分比计算
                priceChangePercentage = currentPrice.subtract(previousPrice)
                        .divide(previousPrice, 4, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100));
            }

            // 计算涨跌值变化
            BigDecimal priceChange = currentPrice.subtract(previousPrice);

            StFundMovement fundMovement = fundMovementMapper.queryByCode(fundCode);
            if (null == fundMovement) {
                // 存储随机记录的值
                StFundMovement movement = new StFundMovement();
                movement.setFundCode(fundCode);
                movement.setPrice(currentPrice.setScale(2, RoundingMode.HALF_UP));
                movement.setUp(priceChangePercentage.setScale(2, RoundingMode.HALF_UP)); // 设置涨跌幅百分比
                movement.setChange(priceChange.setScale(2, RoundingMode.HALF_UP)); // 设置涨跌值变化
                movement.setCreateTime(new Date());
                fundMovementMapper.insert(movement);

            }

            previousPrice = currentPrice; // 更新上一次的价格为当前价格
            // 更新最大值和最小值
            if (currentPrice.compareTo(high) > 0) {
                high = currentPrice;
            }
            if (currentPrice.compareTo(low) < 0) {
                low = currentPrice;
            }
            // 获取开盘价
            if (i == 0) {
                open = currentPrice;
                // 第一次循环需要给low赋值
                low = currentPrice;
            }
            if (i == 4) {
                close = currentPrice;
            }

        }

        BigDecimal amount = (open.add(high).add(low).add(close)).divide(BigDecimal.valueOf(4), RoundingMode.HALF_UP).multiply(volumeBigDecimal);

        // 储存K线数据  每天只能存储一条数据
        StFundKline kline = fundKlineMapper.queryCurrentKlineData(fundId);
        if (null == kline) {
            StFundKline fundKline = new StFundKline();
            fundKline.setFundCode(fundCode);
            fundKline.setHigh(high.setScale(2, RoundingMode.HALF_UP));
            fundKline.setLow(low.setScale(2, RoundingMode.HALF_UP));
            fundKline.setOpen(open.setScale(2, RoundingMode.HALF_UP));
            fundKline.setClose(close.setScale(2, RoundingMode.HALF_UP));
            fundKline.setTurnover(amount.setScale(2, RoundingMode.HALF_UP));
            fundKline.setVolume(volumeBigDecimal.setScale(2, RoundingMode.HALF_UP));
            fundKline.setTimestamp(System.currentTimeMillis() / 1000);
            fundKlineMapper.insert(fundKline);

            // 更新该基金当前价格
            StFund updateFund = new StFund();
            BigDecimal currentPrice = close.setScale(2, RoundingMode.HALF_UP);
            updateFund.setCurrentPrice(currentPrice);
            UpdateWrapper<StFund> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("fund_code", fundCode);
            fundMapper.update(updateFund, updateWrapper);

        }else {
            // 更新该基金当前价格
            StFund updateFund = new StFund();
            BigDecimal currentPrice = kline.getClose().setScale(2, RoundingMode.HALF_UP);
            updateFund.setCurrentPrice(currentPrice);
            UpdateWrapper<StFund> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("fund_code", fundCode);
            fundMapper.update(updateFund, updateWrapper);
        }

    }

    /**
     * 定时更新用户持有基金的收益
     */
//    @PostConstruct
//    @Scheduled(cron = "0 0 13 * * ?")
    public void calculateAllFund(){
        log.info("更新用户持有基金的收益开始执行");
        // 查询出所有的基金信息，进行模拟K线
        QueryWrapper<StFund> stFundQueryWrapper = new QueryWrapper<>();
        stFundQueryWrapper.eq("status", "1");
        List<StFund> stFunds = fundMapper.selectList(stFundQueryWrapper);

        for (StFund stFund : stFunds) {
            // 当前价格
            Integer fundId = stFund.getId();
            BigDecimal currentPrice = stFund.getCurrentPrice();
            calculateTheIncomeOfHoldingFund(fundId, currentPrice);
        }
        log.info("更新用户持有基金的收益结束执行");
    }

    private void calculateTheIncomeOfHoldingFund(Integer fundId, BigDecimal currentPrice){

        // 查询所有用户的购买记录
        QueryWrapper<StFundApply> wrapper = new QueryWrapper<>();
        wrapper.eq("fund_id", fundId);
        List<StFundApply> stFundApplies = stFundApplyMapper.selectList(wrapper);
        for (StFundApply apply : stFundApplies) {
            BigDecimal purchaseShare = apply.getPurchaseShare();
            if (purchaseShare.compareTo(BigDecimal.ZERO) <= 0) {
                continue;
            }

            StFundApply updateApply = new StFundApply();
            updateApply.setId(apply.getId());
            // 当前净额 * 持有份额
            BigDecimal purchaseAmount = purchaseShare.multiply(currentPrice);
            updateApply.setPurchaseAmount(purchaseAmount);
            updateApply.setEndTime(new Date());
            stFundApplyMapper.updateById(updateApply);
        }


    }

//    /**
//     * 更新符合条件的(买入的第二天开始计算收益) 所有用户持有基金的收益
//     */
////    @PostConstruct
//    @Scheduled(cron = "0 0/5 * * * ?")
//    public void calculateTheIncomeOfHoldingFund(){
//
//        // 查询所有用户持有该基金
//        QueryWrapper<StFundApply> applyQueryWrapper = new QueryWrapper<>();
//        List<StFundApply> userFunds = stFundApplyMapper.selectList(applyQueryWrapper);
//        // 遍历所有用户持有该基金
//        for (StFundApply userFund : userFunds) {
//            Integer fundId = userFund.getFundId();
//            // 查询当日K线数据
//            StFundKline kline = fundKlineMapper.queryCurrentKlineData(fundId);
//            if (null == kline) {
//                continue;
//            }
//
//            BigDecimal open = kline.getOpen();
//            BigDecimal close = kline.getClose();
//
//            // 根据当天的涨跌幅百分比  计算用户持有基金的收益情况
//            // 计算涨跌幅比例  (昨收价格 -  开盘价) / 昨收价格
//            BigDecimal changePercent = open.subtract(close).divide(close, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
//            // 盈亏
//            BigDecimal profitAndLoss = userFund.getProfitAndLoss();
//
//            // 查询符合条件的基金的金额(购买后的第二天才可计算收益)
//            String orderNumber = userFund.getOrderNumber();
//            String purchaseAmount = stFundApplyDetailMapper.getPurchaseAmount(orderNumber);
//            BigDecimal purchaseAmountDecimal = new BigDecimal(purchaseAmount);
//            // 有可能 还没计算收益  就已经卖出了 导致数据为负数  只有大于0的数据计算收益才有意义
//            if (purchaseAmountDecimal.compareTo(BigDecimal.ZERO) > 0) {
//                // 计算涨跌幅金额  涨跌幅比例 * 用户持有基金的总金额
//                BigDecimal changeAmount = changePercent.multiply(purchaseAmountDecimal).setScale(2, RoundingMode.HALF_UP).divide(BigDecimal.valueOf(100));
//                // 原来的盈亏加上这次的涨跌幅金额
//                profitAndLoss = profitAndLoss.add(changeAmount);
//                userFund.setProfitAndLoss(profitAndLoss);
//                // 更新用户持有基金的盈亏
//                stFundApplyMapper.updateById(userFund);
//            }
//
//        }
//
//    }

    /**
     * 更新符合条件的基金赎回(卖出的第二天到账)
     */
    @PostConstruct
    @Scheduled(cron = "0 0/5 * * * ?")
    public void updateEligibleFundRedemption(){
        log.info("############更新符合条件的基金赎回开始###################");

        // 卖出类型的基金记录 卖出时间 大于等于 第二天的时间
        List<StFundApplyDetail> fundApplyDetails = stFundApplyDetailMapper.queryEligibleFundRedemption();
        for (StFundApplyDetail detail : fundApplyDetails){
            // 卖出的基金价格
            BigDecimal purchaseAmount = detail.getPurchaseAmount();
            // 卖出的钱回配资账户
            Integer userId = detail.getUserId();
            User user = userMapper.selectByPrimaryKey(userId);
            if (null != user) {
                // 退钱到对应的账户
                returnCorrespondAccount(user, purchaseAmount);

                // 记录资金详情
                UserCashDetail ucd = new UserCashDetail();
                ucd.setAgentId(user.getAgentId());
                ucd.setAgentName(user.getAgentName());
                ucd.setUserId(user.getId());
                ucd.setUserName(user.getRealName());
                ucd.setDeType("Sell fund");
                ucd.setDeSummary(user.getNickName() + " : " + DateUtils.now() + "  sell fund, Amount sold：" + purchaseAmount);
                ucd.setDeAmt(purchaseAmount);
                ucd.setAddTime(new Date());
                ucd.setIsRead(Integer.valueOf(0));
                userCashDetailMapper.insert(ucd);

                // 更新状态为已卖出
                detail.setTradeType(StFundApplyDetail.STATUS_SELL_SUCCESS);
                stFundApplyDetailMapper.updateById(detail);
            }
        }
        log.info("############更新符合条件的基金赎回结束###################");
    }

    // 模拟基金价格变动
    public void simulatePriceChange() {
        Random random = new Random();
        double fluctuation = random.nextDouble() * MAX_FLUCTUATION * 2 - MAX_FLUCTUATION; // 生成随机波动
        double slowTrend = SLOW_TREND; // 缓慢上涨的趋势

        // 计算下一个价格
        double nextPrice = currentPrice + fluctuation + slowTrend;

        // 确保价格不会小于等于 0
        if (nextPrice > 0) {
            currentPrice = nextPrice;
        }

        System.out.println("当前基金价格：" + currentPrice);
    }

    private int returnCorrespondAccount(User user, BigDecimal reckonEnable){
        // 查询用户配资记录 总的配资金额
        Integer userId = user.getId();
        Integer amount = fundsApplyMapper.getUserTotalAmountOfFunds(userId);
        if (null == amount) {
            // 配资账户未激活 直接退还到可用资金
            BigDecimal enableAmt = user.getEnableAmt();
            enableAmt = enableAmt.add(reckonEnable);

            User updateUser = new User();
            updateUser.setId(userId);
            updateUser.setEnableAmt(enableAmt);
            return userMapper.updateByPrimaryKeySelective(updateUser);
        }

        // 用户总的配资金额
        BigDecimal fundsAmount = new BigDecimal(amount);
        // 用户目前持有的配资金额  不包含保证金
        BigDecimal tradingAmount = user.getTradingAmount();
        BigDecimal enableAmt = user.getEnableAmt();

        // 需要退还到配资账户的钱
        BigDecimal fundsReturn = fundsAmount.subtract(tradingAmount);
        // 如果卖出股票的钱大于已使用的配资的钱，就先退还配资的钱，然后将剩余的退还到可用资金
        if (reckonEnable.compareTo(fundsReturn) > 0) {
            tradingAmount = tradingAmount.add(fundsReturn);

            // 卖出的钱如果有剩余需要退还到可用金额
            BigDecimal available = reckonEnable.subtract(fundsReturn);
            if (available.compareTo(BigDecimal.ZERO) > 0) {
                enableAmt = enableAmt.add(available);
            }
        }else {
            tradingAmount = tradingAmount.add(reckonEnable);
        }

        User updateUser = new User();
        updateUser.setId(userId);
        updateUser.setTradingAmount(tradingAmount);
        updateUser.setEnableAmt(enableAmt);
        return userMapper.updateByPrimaryKeySelective(updateUser);
    }
    private static long getNextExecutionTime(long currentTimeMillis) {
        // 获取今天的午夜时间戳
        long todayMidnight = currentTimeMillis - (currentTimeMillis % (24 * 60 * 60 * 1000));
        // 加上一天的时间
        long nextDayMidnight = todayMidnight + (24 * 60 * 60 * 1000);
        return nextDayMidnight;
    }

    public static void main(String[] args) {
//        FundSimulatorComponent simulator = new FundSimulatorComponent();
//
//        // 模拟基金价格变动，可根据需要调整循环次数或时间间隔
//        for (int i = 0; i < 1; i++) {
//            simulator.simulatePriceChange();
////            try {
////                Thread.sleep(1000); // 模拟每秒钟更新一次价格
////            } catch (InterruptedException e) {
////                e.printStackTrace();
////            }
//        }

        List<Long> generatedData = generateData(10); // 生成最近10天的数据
        for (long item : generatedData) {
            System.out.println(item);
        }


    }


    public static List<Long> generateData(int days) {
        List<Long> data = new ArrayList<>();
        Random random = new Random();

        for (int i = 0; i < days; i++) {
            // 生成随机数据
            long randomData = random.nextLong();
            // 将数据的生成时间设置为当前天的开始时间戳
            long timestamp = getStartOfDayTimestamp(i) / 1000;
            // 存储数据和对应的时间戳
            data.add(timestamp);
//            data.add(randomData);
        }

        return data;
    }

    private static long getStartOfDayTimestamp(int daysBeforeNow) {
        long currentTime = System.currentTimeMillis();
        // 计算指定天数之前的开始时间戳
        long startOfDayTimestamp = currentTime - (currentTime % (24 * 60 * 60 * 1000)) - (daysBeforeNow * 24 * 60 * 60 * 1000);
        return startOfDayTimestamp;
    }

}
